import dayjs from "dayjs";
import config from "@/config";
import store from "@/store";
import sm from "@/utils/ScheduleManage/operate";
import fso from "@/utils/FileOperate/operate";
import StateCodeMap from "@/utils/websocket/stateCodeMap";
import { startTask, stopTask } from "@/utils/cron";
import { testNetInfo, listFailCmd } from "@/api/home";
import { getEntryNetworkInfo } from "@/utils/entryNetworkInfoOperate";
import { Module } from "@/utils/nativeModules";
import { uploadData } from "@/api/websocket";
import handleWSCmd from "@/utils/websocket/handleWSCmd";
import semver from "semver";

import { destroy as websocketDestroy, connect as websocketConnect, setWsConnect } from "@/utils/websocket/index";

import type { DeviceCmdType } from "@/typings/businessType";

const CHECK_NAME = "CHECK";

// 全局定时检查 cron
export default () => {
  stopTask(CHECK_NAME);
  startTask(CHECK_NAME, config.checkCronExpr, async (taskName, cronExpr) => {
    try {
      const msg = `触发 cron 任务, 任务名称: 【${taskName}】, 对应的表达式: 【${cronExpr}】`;
      fso.info(msg);
      // TODO 会导致后台出现 Socket Closed 报错导致设备离线
      // if (store.getState().index.isWebsocketConnect) {
      //   websocketDestroy();
      //   setWsConnect(false);
      // }
      // setTimeout(() => {
      //   fso.info("定时重连websocket");
      //   websocketConnect();
      // }, 500);

      const hh = dayjs().format("HH");
      // 检查是否需要同步排期
      if (config.autoSyncScheduleDate.includes(hh)) {
        fso.info(`当前时间符合定时同步排期时间【${config.autoSyncScheduleDate.join(" | ")}】`);
        await testNetInfo();

        const flag = await sm.syncSchedule().catch(err => {
          fso.error("排期数据定时同步失败", err);
        });

        if (flag) {
          fso.info("排期数据定时同步成功");
        } else {
          fso.error("排期数据定时同步失败");
        }
      }

      // 检查离线升级指令
      if (config.autoUploadAppDate.includes(hh)) {
        fso.info(`当前时间符合定时检查升级APP【${config.autoUploadAppDate.join(" | ")}】`);
        await testNetInfo();
        checkAppUpdate();
      }
    } catch (err) {
      fso.error(`【${CHECK_NAME}】定时任务触发出错了: `, err);
    } finally {
      console.log(`【${CHECK_NAME}】定时任务触发完成`);
    }
  });
};

/** 检查app离线升级指令 */
export async function checkAppUpdate() {
  try {
    const isRoot = await Module.isRoot();
    if (!isRoot) {
      fso.warn("当前设备没有ROOT权限, 不进行自动升级");
      return;
    }
    const entryNetworkInfo = await getEntryNetworkInfo();
    if (entryNetworkInfo) {
      const offLineCmdDatas: DeviceCmdType[] = await listFailCmd(
        entryNetworkInfo.code,
        StateCodeMap.UPDATE_APP.toString()
      ).then(res => res.data);
      if (offLineCmdDatas.length) {
        fso.info("查询所有的离线升级指令: ", offLineCmdDatas);
        let target = offLineCmdDatas[0];
        if (offLineCmdDatas.length > 1) {
          offLineCmdDatas.forEach(e => {
            // 取最大的就是最后的
            if (Number(target.batchId) > Number(e.batchId)) target = e;
          });
        }

        // 无论成功还是失败都先回传数据, 因为安装成功后会导致应用重启, 无法回传数据
        for (let i = 0; i < offLineCmdDatas.length; i++) {
          const item = offLineCmdDatas[i];
          const itemData = JSON.parse(item.msg || "{}");
          await uploadData({
            batchId: item.batchId,
            deviceCode: item.deviceCode,
            cmd: String(item.cmd),
            data: JSON.stringify({
              ...(itemData || {}),
              cmd: item.cmd,
              backTime: Date.now() // 返回数据时间戳
            })
          });
        }
        const targetData = JSON.parse(target.msg || "{}");
        const updateVersionUrl = targetData?.updateVersionUrl;
        if (!updateVersionUrl) {
          fso.warn("没有获取到参数【updateVersionUrl】");
          return;
        }

        // http://1.12.69.30:9000/m180/apks/com_mlkj_mip_1.3.1_2024_05_23.apk
        fso.info("下载地址URL: ", updateVersionUrl);

        const [, fileName] = updateVersionUrl.split("/apks/");
        if (!fileName) {
          fso.warn("没有从下载地址中截取出文件名称, 请检查是否是在 /apks/xxx 下面");
          return;
        }

        const _appInfo = await Module.getAppInfo();
        if (_appInfo) {
          // 截取URL中的版本
          const packageName = _appInfo.packageName.replaceAll(".", "_") + "_";
          const [version] = fileName.replace(packageName, "").split("_");
          fso.info("从下载地址中截取出版本信息: ", version);
          fso.info("APP当前的版本信息: ", _appInfo.versionName);

          // 大于或者等于
          const flag = semver.gte(version, _appInfo.versionName);
          if (flag) {
            handleWSCmd({
              cmd: target.cmd,
              data: targetData,
              msg: "离线执行的升级指令"
            });
          } else {
            fso.warn(`版本必须大于或者等于当前APP版本`);
          }
        } else {
          fso.warn("APP信息获取失败");
        }
      } else {
        fso.info("没有查询到需要离线升级指令");
      }
    } else {
      fso.warn("本地没有获取到入网信息");
    }
  } catch (err) {
    fso.error("检查离线升级指令失败: ", err);
  }
}
